package com.qinghe.pro.util.redis;

import java.util.List;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class RedisAspect {
	private static Logger logger = LoggerFactory.getLogger(RedisAspect.class);

	@Autowired
	private RedisUtil redisUtil;

	/**
	 * 方法调用前，先查询缓存。如果存在缓存，则返回缓存数据，阻止方法调用;
	 * 
	 * @param pjp
	 * @param redisCache
	 * 
	 * @return
	 * @throws Throwable
	 * @author longfei
	 */
	@Around("@annotation(redisCache)")
	public Object cache(ProceedingJoinPoint pjp, RedisCache redisCache) throws Throwable {
		// 得到类名、方法名和参数
		//String clazzName = pjp.getSignature().getDeclaringTypeName();
		String clazzName = pjp.getTarget().getClass().getName();
		String methodName = pjp.getSignature().getName();
		Object[] args = pjp.getArgs();
		String hashKey = getCacheKey(clazzName, methodName, args);
		String key = redisCache.type().getName();
		long expired = redisCache.expire();
		Object value = redisUtil.get(key, hashKey);
		// 缓存命中
		if (null != value) {
			return value;
		}
		// 缓存未命中
		value = pjp.proceed();
		if (expired <= 0) {
			redisUtil.put(key, hashKey, value);
		} else {
			redisUtil.put(key, hashKey, value, expired);
		}
		return value;
	}

	/**
	 * 在方法调用前清除缓存，然后调用业务方法
	 * 
	 * @param pjp
	 * @param redisEvict
	 * 
	 * @return
	 * @throws Throwable
	 * @author longfei
	 */
	@Around("@annotation(redisEvict)")
	public Object evictCache(ProceedingJoinPoint pjp, RedisEvict redisEvict) throws Throwable {
		String key = redisEvict.type().getName();
		logger.debug("清空缓存:" + key);
		redisUtil.remove(key);
		return pjp.proceed();
	}

	/**
	 * 获取缓存key
	 * 
	 * @param clazzName 类名
	 * @param methodName 方法名
	 * @param args 参数
	 * 
	 * @return
	 * @author longfei
	 */
	private String getCacheKey(String clazzName, String methodName, Object[] args) {
		StringBuilder sb = new StringBuilder();
		sb.append(clazzName).append(".").append(methodName);
		for (Object obj : args) {
			if (obj instanceof List<?>) {
				for (Object ob : ((List<?>) obj)) {
					sb.append(".").append(ob.toString());
				}
			} else {
				if (null != obj && "" != obj)
					sb.append(".").append(obj.toString());
			}
		}
		return sb.toString();
	}

}
